package com.eslserver.core;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import static org.quartz.impl.matchers.EverythingMatcher.allTriggers;

import java.util.Collection;
import java.util.List;

import javax.servlet.ServletException;

import org.hibernate.Session;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eslserver.action.schedule.job.PushScheduleJob;
import com.eslserver.action.schedule.listener.PushScheduleTriggerListener;
import com.eslserver.core.aware.ScheduleAware;
import com.eslserver.dao.ESLServerDAOFactory;
import com.eslserver.dao.ScheduleDAO;
import com.eslserver.to.Schedule;
import com.eslserver.util.HibernateUtil;

public class ScheduleTimerInitializer implements ScheduleAware {
	public static final Logger LOG = LoggerFactory
			.getLogger(ScheduleTimerInitializer.class);
	private static Scheduler sched;

	public static void initScheduleTimer() {
		try {
			StdSchedulerFactory schedFact = new StdSchedulerFactory();
			schedFact.initialize("guiserver.properties");

			if (sched == null) {
				sched = schedFact.getScheduler();
			} else {
				sched.clear();
			}

			sched.getListenerManager().addTriggerListener(
					new PushScheduleTriggerListener(), allTriggers());

			try {
				Session session = HibernateUtil.getSessionFactory()
						.getCurrentSession();
				session.beginTransaction();
				ScheduleDAO scheduleDAO = ESLServerDAOFactory.getDAOFactory(
						ESLServerDAOFactory.ESLSERVER_DAOFACTORY)
						.getScheduleDAO();

				Collection<Schedule> allSchedule = scheduleDAO
						.loadAllSchedules();

				for (Schedule schedule : allSchedule) {
					addScheduleTimer(schedule);
				}
				session.getTransaction().commit();
			} catch (Throwable e) {
				HibernateUtil.getSessionFactory().getCurrentSession()
						.getTransaction().rollback();
				throw new ServletException(e);
			}

			sched.start();

		} catch (Exception e) {
			LOG.error("Timer initialization failed", e);
		}
	}

	public static void addScheduleTimer(Schedule schedule) {
		JobDetail job = newJob(PushScheduleJob.class)
				.withIdentity(
						schedule.getScheduleID() + ":" + schedule.getName())
				.usingJobData(ATTRIBUTE_SCHEDULE_ID, schedule.getScheduleID())
				.build();

		deleteScheduleTimer(schedule);

		Trigger trigger = null;
		if (!schedule.isRepeat()) {
			trigger = newTrigger()
					.startAt(schedule.getStartTime())
					.withSchedule(
							simpleSchedule()
									.withMisfireHandlingInstructionFireNow())
					.build();
		} else {
			trigger = newTrigger()
					.startAt(schedule.getStartTime())
					.withSchedule(
							simpleSchedule()
									.withIntervalInSeconds(
											schedule.getTimeInterval())
									.repeatForever()
									.withMisfireHandlingInstructionNextWithExistingCount())
					.build();
		}
		try {
			sched.scheduleJob(job, trigger);
		} catch (SchedulerException e) {
			LOG.error("Add ScheduleTimer failed", e);
		}
	}

	public static void deleteScheduleTimer(Schedule schedule) {
		try {
			sched.deleteJob(new JobKey(getJobKeyName(schedule)));
		} catch (SchedulerException e) {
			LOG.error(e.getMessage(), e);
		}
	}

	public static String getJobKeyName(Schedule schedule) {
		return schedule.getScheduleID() + ":" + schedule.getName();
	}

	public static List<? extends Trigger> getTriggerDetailByJobKey(
			Schedule schedule) {
		List<? extends Trigger> triggers = null;
		try {
			triggers = sched.getTriggersOfJob(new JobKey(
					getJobKeyName(schedule)));
		} catch (SchedulerException e) {
			LOG.error(e.getMessage(), e);
		}
		return triggers;
	}
}
